home *** CD-ROM | disk | FTP | other *** search
- Path: news.ioffe.rssi.ru!usenet
- From: "Eugene I Levin" <Levin@lh.ioffe.rssi.ru>
- Newsgroups: comp.lang.c,comp.lang.c++
- Subject: Re: RANDOM NUMBER GENERATOR
- Date: Thu, 4 Jan 1996 00:12:10 +0300 (MSK)
- Organization: Ioffe Institute
- Distribution: world
- Message-ID: <ABg4lwmmK4@lh.ioffe.rssi.ru>
- NNTP-Posting-Host: ccpti.ioffe.rssi.ru
- Mime-Version: 1.0
- Content-Transfer-Encoding: 8bit
- X-Mailer: dMail [Demos Mail for DOS v1.23]
-
- BCNJ68B@prodigy.com (Tom Kellerman) wrote:
-
- > I want to thank you all for your responses. I am going to try and put
- > something together. I have tried to use just the RAND() and SRAND()
- > functions , but for some reason the result I get after 1M+ rolls the
- > numbers I am getting do not appear random. Maybe I am wrong, I don't
- > know.
-
- Tom, you are RIGHT! The congruent generator which is employed in
- rand() is the bad one! And everybody know that. I followed this
- discussion with a kind of growing surprise: people cite Knuth's book as
- if there was nothing new about random number generation during 25
- years! BTW, the book is old but very good, and the summary of 500+
- pages Knuth wrote about congruent generators is: "If you need a
- generator for something serious, use shuffling algorithm" ("Algorithm
- MIX" from his book, if I recall the name correctly). I mean Knuth's
- MIX, not the strange algorithm "from MS Developer Network" somebody
- cited. Knuth's MIX is good, but slow.
-
- Knuth wrote his best in 1970, but then in late seventies the old shift-
- register algorithm was re-invented, and I thought that this closed the
- discussion about which generator is better (at least for simulating
- purposes: cryptography people have their own considerations). At least
- I use nothing but this algorithm since 1980 and it proved to be
- trustful in a few very complex multi-dimensional problems.
-
- Here is source of C function I use (I also have a FORTRAN version).
- Use it and forget rand(). Further details you can find in "T.G.Lewis &
- W.H.Payne. Generalized Feedback Shift Register Pseudorandom Number
- Algorithm. - Journal of ACM, 1973, vol 20, N3, pp. 456-468.". Sorry, I
- don't have more modern references at hand, but you can find them in
- any university library computer searching for "Shift Register Random".
-
- Best regards, Eugene
-
- *--> CUT HERE <----> CUT HERE <----> CUT HERE <----> CUT HERE <--*
-
- extern void sr250s (unsigned);
- extern float sr250f ();
- extern int sr250l (unsigned);
- extern int sr250i (unsigned short);
-
- /*
-
- DESCRIPTION:
- Shift-register Random Number Generator.
-
- Copyleft (c) 1987, 1992. Eugene I Levin, A.F.Ioffe institute,
- St. Petersburg, Russia.
- E-mail: Levin@lh.ioffe.rssi.ru
-
- This is a public domain program and may be freely distributed under the
- condition of remaining the original Copyleft information.
-
- The author would appreciate to be informed about any improvements of
- these functions, or their implementations for any other computer system.
-
- TESTS:
- These functions have been tested on a i860 computer with GNU C compiler
- and on 80486 computer with Borland C++. The main generator engine and
- it's integer entries are more or less machine-independent. The float
- entry, sr250f() should work on any computer were the type float occupies
- 4 bytes and follows IEEE standards.
-
- REALIZATION NOTES:
- This is a realization of standard shift-register algorithm for random
- bit streams:
- x[n] = x[n-q] XOR x[n-p] (1)
- where p and q satisfy the condition that the polynomial x^p + x^q + 1
- must be primitive on the GF(2) field. There are a few known pairs (p,
- q), p = 250 and q = 103 has been used.
-
- In order to generate float numbers independent bit streams (1) are used
- for the each bit of mantissa.
-
- Consecutive values of (1) are stored in array "buffer" of the length p.
- The index of the n-th member of (1) in buffer is
- i = n mod p (2)
- so that a new value x[n] always replaces x[n-p]. Substitution of Eq. (2)
- into Eq. (1) yields to the algorithm:
- x[i] = x[i] XOR x[i - p] when i >= p, (3a)
- x[i] = x[i] XOR x[i - p + q] when i < p. (3b)
-
- */
- #include <stdlib.h>
-
- #define P 250
- #define Q 103
-
- #define Q1 (P-Q)
- #define MANTISSA_MASK 0x003fffffl
- #define INT_MASK 0x0000ffffl
- #define FLOAT_2 0x40000000l /* (float) 2 */
-
- static union {
- float f;
- long l;
- } mixer;
-
- static long buffer[P]; /* the buffer described above */
- static int index; /* pointer to the current cell in the buffer */
- static int i; /* working variable */
-
- /*
- The following macro is the engine of the generator. It tests whether
- there is an unused value in the buffer and, if there is not, replaces
- the whole buffer with fresh values according to formulae (3).
-
- */
-
- #define REFRESH \
- if (index == P) \
- { \
- index = 0; \
- for (i=0; i<Q; i++) buffer[i] ^= buffer[i+Q1]; \
- for (i=Q; i<P; i++) buffer[i] ^= buffer[i-Q]; \
- }
-
- /*====================================================================*/
-
- void sr250s(unsigned seed)
-
- /* This function fills the buffer with initial values taken from the
- system generator (members -p through 0 of the sequence (1)).
- sr250u *MUST* be called before any call to other sr250 functions.
- Parameter "seed" determines the sequence of random numbers. */
-
- {
- #define longrand ((long) rand())
-
- srand(seed);
- for (i=0; i<P; i++)
- buffer[i] = (longrand | (longrand<<15)) & MANTISSA_MASK;
- index = P; /* Marks the buffer as already used */
-
- }
-
- /*====================================================================*/
-
- float sr250f()
- /* Generates a random float 0 <= x < 1. */
- {
- REFRESH
- mixer.l = buffer[index++] | FLOAT_2;
- return (mixer.f - 2.0);
- /* Floats on computers which follow IEEE float-point standards
- (Intel, Sun) are stored without first bit in their mantissas
- (which is supposed to equal 1), thus mixer.f belongs to the
- interval [2, 3], not to [2, 4] as it would be on a "classic"
- computer. */
- }
-
- /*====================================================================*/
-
- int sr250i(unsigned short m)
-
- /* Generates an integer 0 <= i < m. */
-
- {
- REFRESH
- return (int) (((buffer[index++] & INT_MASK)*m)>>16);
- }
-
- /*====================================================================*/
-
- int sr250l(unsigned l1)
- /*
- Generates an integer 0 <= i <= l1, where l1 *MUST* equal 2^n - 1.
- This entry is somewhat faster than sr250i.
- */
- {
- REFRESH
- return (int) (buffer[index++] &((long) l1));
- }
-
- --
- ===============================================================
- Eugene I Levin, St.Petersburg, Russia (Levin@lh.ioffe.rssi.ru).
-
-